package com.cfweb.api;

import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpSession;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.elasticsearch.common.mvel2.ast.WithNode.ParmValuePair;
import org.elasticsearch.common.xcontent.ToXContent.Params;

import com.cfweb.controller.LoginHandler;
import com.cfweb.exception.CloudFoundryApiException;
import com.cfweb.util.CloudFoundryClientUtil;
import com.cfweb.util.HttpClientResponse;
import com.cfweb.util.HttpStatusUtil;
import com.cfweb.util.JsonUtil;
import com.cfweb.util.StringUtil;

public class RouteApi {
	
	static Logger logger = Logger.getLogger(OrgApi.class);
	
	/**
     * get all of routes
     * @param session
     * @return List<Map<String, Object>>
     * @throws Exception 
     */
	@SuppressWarnings("unchecked")
	public static List<Map<String, Object>> get_routes(HttpSession session) throws Exception {
		List<Map<String, Object>> res = new ArrayList<Map<String, Object>>();
		try {
			String host = ((URL) session.getAttribute(LoginHandler.TARGET)).toString();
			String urlPath = host + "/v2/routes";
			String content = CloudFoundryClientUtil.doCCGet(urlPath, null, session);
			Map<String, Object> data = JsonUtil.convertJsonToMap(content);
			List<Map<String, Object>> lr = (List<Map<String, Object>>) data.get("resources");
			String next_url = (String) data.get("next_url");
			while (next_url != null) {
				next_url = ApiCommonUtil.retriveAllPageResource(lr, next_url, session);
			}
			for (Map<String, Object> r : lr) {
				Map<String, Object> tmp = new HashMap<String, Object>();
				Map<String, Object> metadata = (Map<String, Object>) r.get("metadata");
				String guid = (String) metadata.get("guid");
				Map<String, Object> entity = (Map<String, Object>) r.get("entity");
				String hostName = (String) entity.get("host");
				String domainId = (String) entity.get("domain_guid");
				String domainName = (String) ((Map<String, Object>) ((Map<String, Object>) entity.get("domain")).get("entity")).get("name");
				tmp.put("guid", guid);
				tmp.put("host", hostName);
				tmp.put("domain", domainName);
				List<Map<String, Object>> apps = (List) entity.get("apps");
				List<String> resapps = new ArrayList<String>();
				for (Map<String, Object> app : apps) {
					resapps.add((String) ((Map<String, Object>) app.get("entity")).get("name"));
				}
				tmp.put("apps", resapps);
				res.add(tmp);
			}
		} catch (Exception e) {
			throw e;
		}
		return res;
	}
	
	/**
     *get routes by space
     * @param session
     * @param orgName
     * @param spaceName
     * @return List<Map<String, Object>>
     * @throws Exception 
     */
	@SuppressWarnings("unchecked")
	public static List<Map<String, Object>> get_routes_by_space(HttpSession session, final String orgName,
			final String spaceName) throws Exception {
		String spaceId;
		spaceId = UserApi.get_space_id(session, orgName, spaceName);
		List<Map<String, Object>> res = new ArrayList<Map<String, Object>>();
		if (StringUtil.isEmpty(spaceId)) {
			return null;
		}
		try {
			String host = ((URL) session.getAttribute(LoginHandler.TARGET)).toString();
			String urlPath = host + "/v2/spaces/" + spaceId + "/routes?inline-relations-depth=1";
			logger.debug(host);
			String content = CloudFoundryClientUtil.doCCGet(urlPath, null, session);
			Map<String, Object> data = JsonUtil.convertJsonToMap(content);
			List<Map<String, Object>> lr = (List<Map<String, Object>>) data.get("resources");
			String next_url = (String) data.get("next_url");
			while (next_url != null) {
				next_url = ApiCommonUtil.retriveAllPageResource(lr, next_url, session);
			}
			for (Map<String, Object> r : lr) {
				Map<String, Object> tmp = new HashMap<String, Object>();
				Map<String, Object> metadata = (Map<String, Object>) r.get("metadata");
				String guid = (String) metadata.get("guid");
				Map<String, Object> entity = (Map<String, Object>) r.get("entity");
				String hostName = (String) entity.get("host");
				String domainName = (String) ((Map<String, Object>) ((Map<String, Object>) entity.get("domain")).get("entity")).get("name");
				tmp.put("guid", guid);
				tmp.put("host", hostName);
				tmp.put("domain", domainName);
				List<Map<String, Object>> apps = (List<Map<String, Object>>) entity.get("apps");
				List<String> resapps = new ArrayList<String>();
				for (Map<String, Object> app : apps) {
					resapps.add((String) ((Map<String, Object>) app.get("entity")).get("name"));
				}
				tmp.put("apps", resapps);
				res.add(tmp);
			}
		} catch (Exception e) {
			throw e;
		}
		return res;
	}
	
	
	/**
     *create a route in the space
     * @param session
     * @param orgName
     * @param spaceName
     * @param domainName
     * @param hostName
     * @return route_guid
     * @throws Exception 
     */
	@SuppressWarnings("unchecked")
	public static String create_route_for_space(HttpSession session, String orgName, 
			String spaceName, String domainName, String hostName) throws Exception {
		String spaceId = UserApi.get_space_id(session, orgName, spaceName);
		if (StringUtil.isEmpty(spaceId)) {
			return null;
		}
		String domainId = DomainApi.get_domain_id(session, orgName, domainName);
		if (domainId.isEmpty()) {
			return null;
		}
		try {
			String content = addRoute(hostName, domainId, spaceId, session);
			Map<String, Object> data = JsonUtil.convertJsonToMap(content);
			return (String) ((Map<String, Object>) data.get("metadata")).get("guid");
		} catch (Exception e) {
			throw e;
		}
	}
	
	/**
     *add a route
     * @param session
     * @param domainGuid
     * @param spaceGuid
     * @param hostName
     * @return 
     * @throws Exception 
     */
	public static String addRoute(String hostName, String domainGuid, String spaceGuid, HttpSession session) throws Exception {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("host", hostName);
		params.put("domain_guid", domainGuid);
		params.put("space_guid", spaceGuid);
		String host = ((URL) session.getAttribute(LoginHandler.TARGET)).toString();
		String urlPath = host + "/v2/routes?async=true&inline-relations-depth=1";
		return CloudFoundryClientUtil.doCCPost(urlPath, params, session);
	}
	
	/**
     * delete a route in the space
     * @param session
     * @param orgName
     * @param spaceName
     * @param domainName
     * @param hostName
     * @return boolean
     * @throws Exception 
     */
	public static boolean delete_route_for_space(HttpSession session, String orgName, 
			String spaceName, String domainName, String hostName) throws Exception {
		String routeId = get_route_id(session, orgName, domainName, hostName);
		if (routeId.isEmpty()) {
			return false;
		}
		try {
			String host = ((URL) session.getAttribute(LoginHandler.TARGET)).toString();
			String urlPath = host + "/v2/routes/" + routeId + "?async=false";
			String content = CloudFoundryClientUtil.doCCDelete(urlPath, null, session);
		} catch (Exception e) {
			throw e;
		}
		return true;
	}
	
	/**
     * map a route
     * @param session
     * @param orgName
     * @param spaceName
     * @param domainName
     * @param hostName
     * @param appName
     * @return boolean
     * @throws Exception 
     */
	public static boolean map_route(HttpSession session, String orgName, String spaceName,
			String domainName, String hostName, String appName) throws Exception {
		String routeId;
		String appId = get_app_id(session, orgName, spaceName, appName);
		routeId = get_route_id(session, orgName, domainName, hostName);
		if (routeId.isEmpty()) {
			return false;
		}
		if (appId.isEmpty()) {
			return false;
		}
		try {
			String host = ((URL) session.getAttribute(LoginHandler.TARGET)).toString();
			String urlPath = host + "/v2/apps/" + appId + "/routes/" + routeId;
			CloudFoundryClientUtil.doCCPut(urlPath, null, session);
		} catch (Exception e) {
			throw e;
		} 
		return true;
	}
	
	/**
     * map a route by guid
     * @param session
     * @param domainGuid
     * @param hostName
     * @param appGuid
     * @return boolean
     * @throws Exception 
     */
	public static boolean map_route_guid(HttpSession session,String domainGuid, String hostName, String appGuid) throws Exception {
		String routeId = get_route_id(session, domainGuid, hostName);
		if (routeId.isEmpty()) {
			return false;
		}
		try {
			String host = ((URL) session.getAttribute(LoginHandler.TARGET)).toString();
			String urlPath = host + "/v2/apps/" + appGuid + "/routes/" + routeId;
			CloudFoundryClientUtil.doCCPut(urlPath, null, session);
		} catch (Exception e) {
			throw e;
		}
		return true;
	}
	
	/**
     * unmap a route
     * @param session
     * @param orgName
     * @param spaceName
     * @param domainName
     * @param hostName
     * @param appName
     * @return boolean
     * @throws Exception 
     */
	public static boolean unmap_route(HttpSession session, String orgName, 
			String spaceName, String domainName, String hostName, String appName) throws Exception {
		String appId = get_app_id(session, orgName, spaceName, appName);
		String routeId = get_route_id(session, orgName, domainName, hostName);
		if (appId.isEmpty()) {
			return false;
		}
		if (routeId.isEmpty()) {
			return false;
		}
		try {
			String host = ((URL) session.getAttribute(LoginHandler.TARGET)).toString();
			String urlPath = host + "/v2/apps/" + appId + "/routes/" + routeId + "?async=false";
			CloudFoundryClientUtil.doCCDelete(urlPath, null, session);
		} catch (Exception e) {
			throw e;
		}
		return true;
	}
	
	/**
     * unmap a route by guid
     * @param session
     * @param domainGuid
     * @param hostName
     * @param appGuid
     * @return boolean
     * @throws Exception 
     */
	public static boolean unmap_route_guid(HttpSession session,String domainGuid, String hostName, String appGuid) throws Exception {
		HttpClient httpClient = null;
		HttpDelete httpDelete = null;
		String routeId = get_route_id(session, domainGuid, hostName);
		if (routeId.isEmpty()) {
			return false;
		}
		try {
			String host = ((URL) session.getAttribute(LoginHandler.TARGET)).toString();
			String urlPath = host + "/v2/apps/" + appGuid + "/routes/" + routeId + "?async=false";	
			httpClient =  new DefaultHttpClient();
			httpDelete = new HttpDelete(urlPath);
			CloudFoundryClientUtil.setAccessHeaders(httpDelete, session);
			HttpResponse response = httpClient.execute(httpDelete);
			if (!HttpStatusUtil.isSuccessStatus(response.getStatusLine().getStatusCode())) {
				HttpEntity entity = response.getEntity();  
				String content = EntityUtils.toString(entity, "UTF-8"); 
				Map<String, Object> data = JsonUtil.convertJsonToMap(content);
				throw new CloudFoundryApiException((Integer) data.get("code"), (String) data.get("description"));
			}
			
			//String content = EntityUtils.toString(entity, "UTF-8"); 
			//userId = (String)((Map<String, Object>)((List)(JsonUtil.convertJsonToMap(content).get("resources"))).get(0)).get("id");
		} catch (Exception e) {
			throw e;
		} finally {
			httpDelete.abort(); 
	        httpClient.getConnectionManager().shutdown();
		}
		return true;
	}
	
	/**
     * get id of a route
     * @param session
     * @param orgName
     * @param hostName
     * @param domainName
     * @return routeId
     * @throws Exception 
     */
	@SuppressWarnings("unchecked")
	public static String get_route_id(HttpSession session, String orgName,
			String domainName, String hostName) throws Exception {
		String domainId;
		domainId = DomainApi.get_domain_id(session, orgName, domainName);
		return get_route_id(session, domainId, hostName);
	}
	
	/**
     * get id of a route by domainGuid
     * @param session
     * @param domainGuid
     * @param hostName
     * @return routeId
     * @throws Exception 
     */
	@SuppressWarnings("unchecked")
	public static String get_route_id(HttpSession session,
			String domainGuid, String hostName) throws Exception {
		try {
			String host = ((URL) session.getAttribute(LoginHandler.TARGET)).toString();
			String urlPath = host + "/v2/routes?inline-relations-depth=1&q=host%3A" 
			+ hostName + "%3Bdomain_guid%3A" + domainGuid;
			String content = CloudFoundryClientUtil.doCCGet(urlPath, null, session);
			Map<String, Object> data = JsonUtil.convertJsonToMap(content);
			List<Map<String, Object>> resources = (List<Map<String, Object>>) data.get("resources");
			if(resources.size() > 0) {
				return (String) ((Map<String, Object>) ((Map<String, Object>) resources.get(0)).get("metadata")).get("guid");
			}
			
		} catch (Exception e) {
			throw e;
		}
		
		return null;
	}
	
	
	/**
     * get id of an application
     * @param session
     * @param spaceName
     * @param orgName
     * @param appName
     * @return appId
     * @throws Exception 
     */
	@SuppressWarnings("unchecked")
	public static String get_app_id(HttpSession session, String orgName,
			String spaceName, String appName) throws Exception {
		String spaceId;
		String appId;
		spaceId = UserApi.get_space_id(session, orgName, spaceName);
		if (StringUtil.isEmpty(spaceId)) {
			return "";
		}
		try {
			String host = ((URL) session.getAttribute(LoginHandler.TARGET)).toString();
			String urlPath = host + "/v2/spaces/" + spaceId + "/apps?q=name%3A"
					+ appName + "&inline-relations-depth=1";
			String content = CloudFoundryClientUtil.doCCGet(urlPath, null, session);
			Map<String, Object> data = JsonUtil.convertJsonToMap(content);
			appId = (String) ((Map<String, Object>) ((Map<String, Object>) ((List) data.get("resources")).get(0)).get("metadata")).get("guid");
		} catch (Exception e) {
			throw e;
		}
		return appId;
	}
	
	/**
     * check a route who is existed or not
     * @param session
     * @param routehost
     * @param orgName
     * @param domain
     * @return boolean
     * @throws Exception 
     */
	@SuppressWarnings("unchecked")
	public static boolean isRouteExist(HttpSession session, String routehost, String orgName, String domain) throws Exception {
		try {
			String host = ((URL) session.getAttribute(LoginHandler.TARGET)).toString();
			String guid = DomainApi.get_domain_id(session, orgName, domain);
			if(guid.isEmpty()) {
				return false;
			}
			String urlPath = host + "/v2/routes?q=host:" + routehost;
			String content = CloudFoundryClientUtil.doCCGet(urlPath, null, session);
			Map<String, Object> data = JsonUtil.convertJsonToMap(content);
			if((int) data.get("total_results") > 0) {
				List<Map<String, Object>> resources = (List<Map<String, Object>>) data.get("resources");
				for(Map<String, Object> resource:resources) {
					Map<String, Object> metadata = (Map<String, Object>) resource.get("entity");
					if(guid.equals(metadata.get("domain_guid"))) {
						return true;
					}
				}
			}
			return false;
		} catch (Exception e) {
			throw e;
		}
	}
	
	/**
     * get size of routes
     * @param session
     * @return size
     * @throws Exception 
     */
	public static int getRouteSize(HttpSession session) throws Exception {
		String host = ((URL) session.getAttribute(LoginHandler.TARGET)).toString();
		String urlPath = host + "/v2/routes";
		String content = CloudFoundryClientUtil.doCCGet(urlPath, null, session);
		Map<String, Object> data = JsonUtil.convertJsonToMap(content);
		return (int) data.get("total_results");
	}

}
